package com.gengzp.ops.service.impl;

import com.gengzp.common.constants.NacosApiUrlConstants;
import com.gengzp.common.exception.BusinessException;
import com.gengzp.common.model.nacos.dto.*;
import com.gengzp.common.model.nacos.entity.NacosConfig;
import com.gengzp.common.model.nacos.entity.YamlConfig;
import com.gengzp.common.model.nacos.req.AddNacosConfigReq;
import com.gengzp.common.model.nacos.req.EditNacosConfigReq;
import com.gengzp.common.model.nacos.req.EditYamlReq;
import com.gengzp.common.model.nacos.req.PageYamlReq;
import com.gengzp.common.model.nacos.resp.PageServiceInstanceResp;
import com.gengzp.common.model.nacos.resp.PageYamlResp;
import com.gengzp.common.model.nacos.resp.SearchNacosConfigResp;
import com.gengzp.common.model.nacos.resp.SearchYamlResp;
import com.gengzp.common.model.pagination.req.PaginationReq;
import com.gengzp.common.model.pagination.resp.PaginationResult;
import com.gengzp.common.utils.RestTemplateUtils;
import com.gengzp.ops.facade.IUserFacadeService;
import com.gengzp.ops.mapper.NacosConfigMapper;
import com.gengzp.ops.mapper.NacosYamlMapper;
import com.gengzp.ops.service.INacosService;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * @ClassName NacosServiceImpl
 * @Description nacos服务治理服务层实现
 * @Author gengzp
 * @Date 2025/5/30 22:10
 */
@Service
public class NacosServiceImpl implements INacosService {

    private static final Logger logger = LoggerFactory.getLogger(NacosServiceImpl.class);

    @Autowired
    private NacosConfigMapper nacosConfigMapper;

    @Autowired
    private NacosYamlMapper nacosYamlMapper;

    @Autowired
    private IUserFacadeService userFacadeService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void addNacosConfig(AddNacosConfigReq req) {
        if (CollectionUtils.isNotEmpty(nacosConfigMapper.selectAllNacosConfigs())) {
            throw BusinessException.get("nacos服务配置已存在, 无法重复添加");
        }

        NacosConfig nacosConfig = new NacosConfig();
        nacosConfig.setNacosAddress(req.getNacosAddress());
        nacosConfig.setNacosNamespace(req.getNacosNamespace());
        nacosConfig.setNacosAccount(req.getNacosAccount());
        nacosConfig.setNacosPassword(req.getNacosPassword());
        nacosConfig.setNacosDescription(req.getNacosDescription());
        nacosConfigMapper.insertNacosConfig(nacosConfig);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void editNacosConfig(EditNacosConfigReq req) {
        NacosConfig nacosConfig = nacosConfigMapper.selectNacosConfigById(Long.valueOf(req.getNacosConfigId()));
        if (Objects.isNull(nacosConfig)) {
            throw BusinessException.get("nacos服务配置不存在");
        }

        nacosConfig.setNacosAddress(req.getNacosAddress());
        nacosConfig.setNacosNamespace(req.getNacosNamespace());
        nacosConfig.setNacosAccount(req.getNacosAccount());
        nacosConfig.setNacosPassword(req.getNacosPassword());
        nacosConfig.setNacosDescription(req.getNacosDescription());
        nacosConfigMapper.updateNacosConfigById(nacosConfig);
    }

    @Override
    public List<SearchNacosConfigResp> searchNacosConfigList() {
        List<NacosConfig> nacosConfigs = nacosConfigMapper.selectAllNacosConfigs();
        if (CollectionUtils.isEmpty(nacosConfigs)) {
            return Collections.emptyList();
        }

        List<SearchNacosConfigResp> result = nacosConfigs.stream()
                .map(this::convertNacosConfigEntity2Resp).collect(Collectors.toList());
        // 填充操作人昵称信息
        userFacadeService.fillInOperatorInfo(result);

        return result;
    }

    @Override
    public SearchNacosConfigResp searchNacosConfigById(Long nacosConfigId) {
        NacosConfig nacosConfig = nacosConfigMapper.selectNacosConfigById(nacosConfigId);
        if (Objects.isNull(nacosConfig)) {
            throw BusinessException.get("nacos服务配置不存在");
        }

        SearchNacosConfigResp result = convertNacosConfigEntity2Resp(nacosConfig);
        // 填充操作人昵称信息
        userFacadeService.fillInOperatorInfo(result);

        return result;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteNacosConfigById(Long nacosConfigId) {
        NacosConfig nacosConfig = nacosConfigMapper.selectNacosConfigById(nacosConfigId);
        if (Objects.isNull(nacosConfig)) {
            throw BusinessException.get("nacos服务配置不存在");
        }

        // 删除nacos配置信息
        nacosConfigMapper.deleteNacosConfigById(nacosConfig);
    }

    @Override
    public PaginationResult<PageYamlResp> pageQueryYamlConfig(PageYamlReq req) {
        List<PageYamlResp> result = Lists.newArrayList();

        List<YamlConfig> yamlConfigs = nacosYamlMapper.pageQueryYamlConfig(req);
        if (CollectionUtils.isEmpty(yamlConfigs)) {
            return PaginationResult.get(result, req);
        }

        for (YamlConfig yamlConfig : yamlConfigs) {
            PageYamlResp resp = new PageYamlResp();
            resp.setYamlName(yamlConfig.getYamlName());
            resp.setYamlDataId(yamlConfig.getYamlDataId());
            resp.setYamlGroup(yamlConfig.getYamlGroup());
            resp.setCreatedTime(yamlConfig.getCreatedTime());
            resp.setLastModifiedTime(yamlConfig.getLastModifiedTime());
            resp.setCreatedBy(String.valueOf(yamlConfig.getCreatedBy()));
            resp.setLastModifiedBy(String.valueOf(yamlConfig.getLastModifiedBy()));
            result.add(resp);
        }
        // 填充操作人字段
        userFacadeService.fillInOperatorInfo(result);

        return PaginationResult.get(result, req);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void syncYamlToDatabase() {
        // 查询系统配置的命名空间
        List<NacosConfig> nacosConfigs = nacosConfigMapper.selectAllNacosConfigs();
        if (CollectionUtils.isEmpty(nacosConfigs)) {
            throw BusinessException.get("未维护nacos配置信息, 无法同步");
        }
        NacosConfig nacosConfig = nacosConfigs.get(0);

        // 先查询所有的nacos yaml配置信息
        PageNacosYamlDto pageNacosYamlDto = RestTemplateUtils.get(
                String.format("%s%s?dataId=&group=&appName=&config_tags=&pageNo=1&pageSize=50&tenant=%s&types=&search=blur",
                        nacosConfig.getNacosAddress(), NacosApiUrlConstants.NACOS_CONFIG_URL, nacosConfig.getNacosNamespace()),
                PageNacosYamlDto.class);
        if (Objects.isNull(pageNacosYamlDto)) {
            throw BusinessException.get("查询nacos yaml配置信息失败");
        }

        // 若没有配置信息, 则直接返回
        if (CollectionUtils.isEmpty(pageNacosYamlDto.getPageItems())) {
            return;
        }

        // 将nacos中配置的信息转换为数据库的yaml配置信息实体
        List<YamlConfig> yamlConfigs = Lists.newArrayList();
        for (SearchNacosYamlItemDto item : pageNacosYamlDto.getPageItems()) {
            YamlConfig yamlConfig = new YamlConfig();
            yamlConfig.setYamlDataId(item.getDataId());
            yamlConfig.setYamlGroup(item.getGroup());
            yamlConfig.setYamlContent(item.getContent());
            yamlConfigs.add(yamlConfig);
        }

        // 要插入的配置集合
        List<YamlConfig> addYamlConfigs = Lists.newArrayList(yamlConfigs);
        // 要编辑的配置集合
        List<YamlConfig> editYamlConfigs = Lists.newArrayList();

        // 查询数据库中已经存在的yaml配置
        List<YamlConfig> existYamlConfigs = nacosYamlMapper.selectYamlConfigByDataIds(
                yamlConfigs.stream().map(YamlConfig::getYamlDataId).collect(Collectors.toList()));
        if (CollectionUtils.isNotEmpty(existYamlConfigs)) {
            // dataId 对应 yaml名称映射
            Map<String, String> dataId2YamlNameMap = existYamlConfigs.stream().filter(v -> StringUtils.isNotBlank(v.getYamlName()))
                    .collect(Collectors.toMap(YamlConfig::getYamlDataId, YamlConfig::getYamlName));
            // 将已存在的dataId赋值yaml名称, 并添加到编辑列表
            yamlConfigs.forEach(v -> {
                String existYamlName = dataId2YamlNameMap.get(v.getYamlDataId());
                if (StringUtils.isNotBlank(existYamlName)) {
                    v.setYamlName(existYamlName);
                }
                editYamlConfigs.add(v);
            });
        }
        addYamlConfigs.removeAll(editYamlConfigs);

        // 插入数据库
        if (CollectionUtils.isNotEmpty(addYamlConfigs)) {
            nacosYamlMapper.batchInsertYamlConfigs(addYamlConfigs);
        }
        // 编辑数据库
        if (CollectionUtils.isNotEmpty(editYamlConfigs)) {
            nacosYamlMapper.batchUpdateYamlConfigsByDataIds(editYamlConfigs);
        }
    }

    @Override
    public SearchYamlResp searchYamlConfigByDataId(String dataId) {
        YamlConfig yamlConfig = nacosYamlMapper.selectYamlConfigByDataId(dataId);
        if (Objects.isNull(yamlConfig)) {
            throw BusinessException.get("yaml配置信息不存在");
        }

        SearchYamlResp result = new SearchYamlResp();
        result.setId(String.valueOf(yamlConfig.getId()));
        result.setYamlDataId(yamlConfig.getYamlDataId());
        result.setYamlGroup(yamlConfig.getYamlGroup());
        result.setYamlName(yamlConfig.getYamlName());
        result.setYamlContent(yamlConfig.getYamlContent());
        result.setCreatedBy(String.valueOf(yamlConfig.getCreatedBy()));
        result.setLastModifiedBy(String.valueOf(yamlConfig.getLastModifiedBy()));
        result.setCreatedTime(yamlConfig.getCreatedTime());
        result.setLastModifiedTime(yamlConfig.getLastModifiedTime());
        // 填充操作人信息
        userFacadeService.fillInOperatorInfo(result);
        return result;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void editYamlConfig(EditYamlReq req) {
        YamlConfig yamlConfig = nacosYamlMapper.selectYamlConfigByDataId(req.getDataId());
        if (Objects.isNull(yamlConfig)) {
            throw BusinessException.get("yaml配置信息不存在");
        }

        // 查询系统配置的命名空间
        List<NacosConfig> nacosConfigs = nacosConfigMapper.selectAllNacosConfigs();
        if (CollectionUtils.isEmpty(nacosConfigs)) {
            throw BusinessException.get("未维护nacos配置信息, 无法同步");
        }
        NacosConfig nacosConfig = nacosConfigs.get(0);

        // 先查询nacos中正在使用的配置信息
        CurrentYamlDto currentYamlConfig = RestTemplateUtils.get(
                String.format("%s%s?dataId=%s&group=%s&namespaceId=%s&tenant=%s&show=all",
                        nacosConfig.getNacosAddress(), NacosApiUrlConstants.NACOS_CONFIG_URL, yamlConfig.getYamlDataId(),
                        yamlConfig.getYamlGroup(), nacosConfig.getNacosNamespace(), nacosConfig.getNacosNamespace()),
                CurrentYamlDto.class);
        if (Objects.isNull(currentYamlConfig)) {
            throw BusinessException.get("nacos中的yaml配置信息不存在");
        }

        // 用编辑后的新yaml更新当前的配置
        Map<String, Object> params = Maps.newHashMap();
        params.put("dataId", currentYamlConfig.getDataId());
        params.put("group", currentYamlConfig.getGroup());
        params.put("content", req.getYamlContent());
        params.put("type", "yaml");
        params.put("id", currentYamlConfig.getId());
        params.put("md5", currentYamlConfig.getMd5());
        params.put("tenant", nacosConfig.getNacosNamespace());
        params.put("createTime", currentYamlConfig.getCreateTime());
        params.put("modifyTime", System.currentTimeMillis());
        Boolean result = RestTemplateUtils.postForm(
                String.format("%s%s", nacosConfig.getNacosAddress(), NacosApiUrlConstants.NACOS_CONFIG_URL),
                params,
                Boolean.class);
        if (!result) {
            throw BusinessException.get("更新nacos配置信息失败");
        }

        // 更新数据库中的yaml配置
        yamlConfig.setYamlName(req.getYamlName());
        yamlConfig.setYamlContent(req.getYamlContent());
        nacosYamlMapper.updateYamlConfigByDataId(yamlConfig);
    }

    @Override
    public PaginationResult<PageServiceInstanceResp> pageQueryServiceInstance(PaginationReq req) {
        // 查询系统配置的命名空间
        List<NacosConfig> nacosConfigs = nacosConfigMapper.selectAllNacosConfigs();
        if (CollectionUtils.isEmpty(nacosConfigs)) {
            throw BusinessException.get("未维护nacos配置信息, 无法同步");
        }
        NacosConfig nacosConfig = nacosConfigs.get(0);

        // 从nacos中查询在线的服务实例
        PageServiceInstanceDto pageServiceInstanceDto = RestTemplateUtils.get(
                String.format("%s%s?hasIpCount=true&withInstances=false&pageNo=%s&pageSize=%s&serviceNameParam=&groupNameParam=&namespaceId=%s",
                        nacosConfig.getNacosAddress(), NacosApiUrlConstants.SERVICE_INSTANCE_URL, req.getPageNum(), req.getPageSize(), nacosConfig.getNacosNamespace()),
                PageServiceInstanceDto.class);
        if (Objects.isNull(pageServiceInstanceDto)) {
            throw BusinessException.get("nacos中查询服务实例失败");
        }

        // 向分页条件中传入数据总条数
        req.setPageCount(pageServiceInstanceDto.getCount());

        List<PageServiceInstanceResp> result = Lists.newArrayList();
        if (CollectionUtils.isNotEmpty(pageServiceInstanceDto.getServiceList())) {
            for (ServiceInstanceDto dto : pageServiceInstanceDto.getServiceList()) {
                PageServiceInstanceResp resp = new PageServiceInstanceResp();
                resp.setServiceName(dto.getName());
                resp.setClusterCount(dto.getClusterCount());
                resp.setGroupName(dto.getGroupName());
                resp.setHealthyInstanceCount(dto.getHealthyInstanceCount());
                result.add(resp);
            }
        }

        return PaginationResult.get(result, req);
    }

    /**
     * 将nacosConfig实体类转换为返回对象
     *
     * @param nacosConfig nacos配置信息
     * @return 返回对象
     */
    private SearchNacosConfigResp convertNacosConfigEntity2Resp(NacosConfig nacosConfig) {
        SearchNacosConfigResp resp = new SearchNacosConfigResp();
        resp.setId(String.valueOf(nacosConfig.getId()));
        resp.setNacosAddress(nacosConfig.getNacosAddress());
        resp.setNacosNamespace(nacosConfig.getNacosNamespace());
        resp.setNacosAccount(nacosConfig.getNacosAccount());
        resp.setNacosPassword(nacosConfig.getNacosPassword());
        resp.setNacosDescription(nacosConfig.getNacosDescription());
        resp.setCreatedBy(String.valueOf(nacosConfig.getCreatedBy()));
        resp.setCreatedTime(nacosConfig.getCreatedTime());
        resp.setLastModifiedBy(String.valueOf(nacosConfig.getLastModifiedBy()));
        resp.setLastModifiedTime(nacosConfig.getLastModifiedTime());
        return resp;
    }

}
